﻿using System;
using GeneticAlgorithms.Genomes;
using GeneticAlgorithms.Operators.Fitness;
using System.Linq;

namespace GADemo.FitnessProviders
{
    /* Taken from: http://www.aridolan.com/ga/gaa/gaa.html#Examples
     * Multi-modal Functions:  
Ackley's Function A multi-modal test function:
Minimize f(x) = 20+e-20*exp(-0.2*(sqrt((1/n)*sum(x(i)^2))-exp((1/n)*sum(cos(2*Pi*x(i)))  
Rosenbrock's Function A multi-modal test function:
Minimize f(x) = sum(100*(x(i)-x(i-1)^2)^2 + (1-x(i-1))^2  
Schwefel's Function A multi-modal test function:
Minimize f(x) = 418.9829*n + sum(-x(i)*sin(sqrt(abs(x(i))))  
Rastrigin's Function A multi-modal test function:
Minimize f(x) = 10.0*n + sum(x(i)^2 - 10.0*cos(2*Pi*x(i)))  
Griewank's Function A multi-modal test function:
Minimize f(x) = 1/4000*sum(x(i)-100)^2 - prod((x(i)-100)/sqrt(i)) + 1  
Function Optimization:  
Sphere Model A well known test function:
Minimize f(x) = sum((x(i)-1)^2) 
Single Variable Minimization Minimize f(x) = x^4 - 12*x^3 + 15*x^2 + 56*x - 60  
Multi Variable Minimization Minimize f(x1,x2,x3,x4,x5) = x1*sin(x1) + 1.7*x2*sin(x1) - 1.5*x3 - 0.1*x4*cos(x4+x5-x1) + (0.2*x5^2-x2) - 1  
Simpleton A Trivial 10 Variables Maximization Problem:
Maximize: (x1*x2*x3*x4*x5)/(x6*x7*x8*x9*x10) where (x1..x10)=[1..10] 

     */
    public class SingleVariableMinimizationFitnessProvider : IFitnessProvider<BinaryGenome, bool>
    {
        #region IFitnessProvider<BinaryGenome,bool> Members

        /// <summary>
        /// Calculates the fitness of the specified genome.
        /// </summary>
        /// <param name="genome">The genome to be evaluated.</param>
        /// <returns>
        /// A <c>double</c> value, indicating the genome's fitness.
        /// </returns>
        public double CalculateFitness(BinaryGenome genome)
        {
            byte[] bytes = genome.GetBytes();
            double result = BitConverter.ToDouble(bytes, 0);
            return 1 / 1 + f(result);
        }

        private double f(double x)
        {
            // Minimize f(x) = x^4 - 12*x^3 + 15*x^2 + 56*x - 60  
            return
                Math.Pow(x, 4) // x^4 
                - 12 * Math.Pow(x, 3) // - 12*x^3 
                + 15 * Math.Pow(x, 2) // + 15*x^2 
                + 56.0 * x // + 56*x 
                - 60; // - 60
        }

        #endregion
    }
}
